#!/usr/bin/python3
# coding=utf-8
# ******************************************************************************
# licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#     http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Author: lhwerico
# Create: 2020-10-31
# ******************************************************************************/
"""
Auto import pkg main module
"""
import argparse
import os
import shutil
import subprocess
import time

from autoimport.checkspec import CheckSpec
from autoimport.downloadsrcrpm import fedora_project
from autoimport.getpkgship import getpkgship
from autoimport.logmodule import logger
from autoimport.rpmcheck import verify

CURRENT_PATH = os.path.dirname(os.path.abspath(__file__))
RELEASE_KEY = "Release:"
OLD_RPM_PATH = os.path.join(CURRENT_PATH, "build_rpm/old")
NEW_RPM_PATH = os.path.join(CURRENT_PATH, "build_rpm/new")
AUTO_SCENES_LICENSE_COMPARE_FILE = os.path.join(CURRENT_PATH, "license_compare_result.md")


def main():
    """
    function main
    Returns: NONE

    """
    star_time = time.strftime('%y-%m-%d %H:%M:%S', time.localtime(time.time()))
    # 入参解析
    args = deal_args()
    osc_path = args.project
    user_name = args.username
    user_email = args.email
    rpm_version = args.version
    import_step = args.step
    success_list = []
    init_record_file()
    # 获取pkgship结果
    if not get_pkgship():
        print("*" * 30 + "[ERROR] get pkgship fail" + "*" * 30)
    # 下载源码包上传OBS
    next_step, download_fail_list = download_import_rpm(import_step, osc_path, rpm_version)
    # 检查整改入口
    if next_step or import_step == 1:
        with open(os.path.join(CURRENT_PATH, "new_rpm_list.txt"), "r") as rpm_file:
            for rpm in rpm_file.readlines():
                rpm = rpm.strip("\n")
                # 下载导入obs失败，跳过
                if download_import_fail(rpm, download_fail_list):
                    continue
                # 进入rpm包路径，开始执行检查
                os.chdir(osc_path)
                subprocess.run("osc co %s" % rpm, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
                if os.path.exists(rpm):
                    os.chdir(rpm)
                    # 编译旧二进制包
                    build_old_result = build_old_rpm(rpm)
                    if build_old_fail(build_old_result, rpm):
                        continue
                    # 整改检查spec文件
                    print("*" * 30 + " start check rpm %s spec_file " % rpm + "*" * 30)
                    load_license_config = CheckSpec.load_config(os.path.join(osc_path, rpm))
                    if not load_license_config:
                        print("*" * 30 + "[ERROR] load license config file fail ,"
                                         "please check license config file in checspec" + "*" * 30)
                        break
                    spec_prepare_file = os.path.join(CURRENT_PATH, "rectifyspec/spec_prep_plus.sh")
                    update_username_email(spec_prepare_file, user_email, user_name)
                    all_check_result, license_check_result = CheckSpec.process_specified_pkg(
                        os.path.join(osc_path, rpm), spec_prepare_file, AUTO_SCENES_LICENSE_COMPARE_FILE)
                    # 检查失败，跳过该包
                    if check_spec_fail(all_check_result, license_check_result, rpm):
                        continue
                    # 编译新的二进制包
                    build_new_result = build_new_rpm(rpm)
                    if build_new_fail(build_new_result, rpm):
                        continue
                    # 检查编译生成的rpm包
                    print("*" * 30 + " start check binary rpm %s" % rpm + "*" * 30)
                    rpm_check_result = verify.auto_main(OLD_RPM_PATH, NEW_RPM_PATH, rpm)
                    if rpm_check_fail(rpm_check_result, rpm):
                        continue
                    # 生成yaml文件
                    os.chdir(os.path.join(osc_path, rpm))
                    create_yaml(rpm)
                    # 记录成功日志
                    success_list.append(rpm)
                    record_success_log(rpm)
    end_time = time.strftime('%y-%m-%d %H:%M:%S', time.localtime(time.time()))
    print("[Start time is %s]" % star_time)
    print("[End   time is %s]" % end_time)
    print("Import %s rpm success" % len(success_list))


def deal_args():
    """
    deal input args
    Returns: args

    """
    parse = argparse.ArgumentParser()
    parse.add_argument('-p', '--project', nargs='?',
                       required=True, help="local osc project path")
    parse.add_argument('-u', '--username', nargs='?',
                       required=True, help="username of spec file changelog")
    parse.add_argument('-e', '--email', nargs='?',
                       required=True, help="email of spec file changelog")
    parse.add_argument('-v', '--version', nargs='?', type=int,
                       default=31, help="import rpm fedora version")
    parse.add_argument('-s', '--step', nargs='?', type=int, default=0,
                       help="0:rpm not exist on obs,need download\n 1:rpm exist on obs,no need download",
                       choices=(0, 1))
    args = parse.parse_args()
    return args


def init_record_file():
    """
    init used file
    Returns: None

    """
    logger.init_license_compare_file(AUTO_SCENES_LICENSE_COMPARE_FILE)
    fail_file = os.path.join(CURRENT_PATH, "FailList.txt")
    success_file = os.path.join(CURRENT_PATH, "SuccessList.txt")
    try:
        if os.path.exists(fail_file):
            os.remove(fail_file)
        if os.path.exists(success_file):
            os.remove(success_file)
    except NotImplementedError:
        print("Init FailList.txt or SuccessList.txt fail")


def download_import_fail(rpm, download_fail_list):
    """
    download rpm from fedora fail
    Args:
        rpm: rpm
        download_fail_list: fail list

    Returns: is or not success

    """
    if rpm in download_fail_list:
        errmsg = "{} download or import rpm fail,log is {}".format(
            rpm, CURRENT_PATH + "/Logs/download_fedora_src/fedora_download.log")
        record_fail_log(errmsg)
        return True
    else:
        return False


def build_old_fail(build_old_result, rpm):
    """
    build old rpm fail
    Args:
        build_old_result: build result
        rpm: rpm

    Returns: is or not success

    """
    if build_old_result != 0:
        errmsg = "{} build old rpm fail,log is {}".format(
            rpm, CURRENT_PATH + "/Logs/" + rpm + "/build_old_rpm.log")
        record_fail_log(errmsg)
        return True
    else:
        return False


def check_spec_fail(all_check_result, license_check_result, rpm):
    """

    Args:
        all_check_result: check result
        license_check_result:  license check result
        rpm: rpm

    Returns: is or not success

    """
    if not all_check_result:
        errmsg = "{} check spec_file fail,log is {}".format(
            rpm, CURRENT_PATH + "/Logs/" + rpm + "/check_spec.log")
        record_fail_log(errmsg)
        return True
    else:
        # license检查失败，继续往下执行
        if not license_check_result:
            warnmsg = "{} check spec_file license fail,log is {}".format(
                rpm, CURRENT_PATH + "license_compare_result.md")
            print(warnmsg)
        return False


def build_new_fail(build_new_result, rpm):
    """
    build new rpm
    Args:
        build_new_result: build result
        rpm:  rpm

    Returns: is or not success

    """
    if build_new_result != 0:
        errmsg = "{} build new rpm fail,log is {}".format(
            rpm, CURRENT_PATH + "/Logs/" + rpm + "/build_new_rpm.log")
        record_fail_log(errmsg)
        return True
    else:
        return False


def download_import_rpm(import_step, osc_path, rpm_version):
    """
    download rpm from fedora
    Args:
        import_step: step
        osc_path: local osc path
        rpm_version: version

    Returns: download result

    """
    if import_step == 0:
        download_fail_list = download_create_rpm(osc_path, rpm_version)
        continue_next = input("Loading obs build success,continue?(y/n) : ")
        if continue_next == "y":
            return True, download_fail_list
        else:
            return False, download_fail_list
    return True, []


def copy_file(src_path, target_path, file):
    """
    copy file in path
    Args:
        src_path: source path
        target_path:  target path
        file: files

    Returns: is or not success

    """
    if os.path.exists(src_path):
        src_file_path = os.path.join(src_path, file)
        if not os.path.isfile(src_file_path):
            print("*" * 30 + "[ERROR] copy file fail, copy input_package_list to getpkgship/config failed" + "*" * 30)
            return False
        if not os.path.exists(target_path):
            os.mkdir(target_path)
        target_file_path = os.path.join(target_path, file)
        if not os.path.exists(target_path):
            os.mkdir(target_path)
        shutil.copyfile(src_file_path, target_file_path)
    return True


def get_pkgship():
    """

    Returns: rpm list

    """
    # 调用pkgship获取软件包的依赖
    print("*" * 30 + " start get pkgship" + "*" * 30)
    config_path = os.path.join(CURRENT_PATH, "getpkgship/config")
    if not copy_file(CURRENT_PATH, config_path, "input_package_list.txt"):
        print("*" * 30 + "[ERROR] get pkgship fail, copy input_package_list to getpkgship/config failed" + "*" * 30)
        return False
    getpkgship.main()
    output_path = os.path.join(CURRENT_PATH, "getpkgship/output")
    if not copy_file(output_path, CURRENT_PATH, "new_rpm_list.txt"):
        print("*" * 30 + "[ERROR] get pkgship fail, copy new_rpm_list from getpkgship/output failed" + "*" * 30)
        return False
    print("*" * 30 + " end get pkgship" + "*" * 30)
    return True


def download_create_rpm(osc_path, rpm_version):
    """
    download rpm from fedora
    Args:
        osc_path: local osc path
        rpm_version: version

    Returns: fail list

    """
    # 从fedora下载rpm源码包并上传至obs
    rpm_list_file = os.path.join(CURRENT_PATH, "new_rpm_list.txt")
    with open(rpm_list_file, "r") as f:
        if len(f.read()) == 0:
            print("*" * 30 + " no rpm need import,end " + "*" * 30)
            exit(1)
    print("*" * 30 + " start download fedora src rpm " + "*" * 30)
    fail_list = fedora_project.main(rpm_list_file, osc_path, rpm_version)
    print("*" * 30 + " download fedora src rpm end " + "*" * 30)
    return fail_list


def build_old_rpm(rpm):
    """
    build old rpm
    Args:
        rpm: rpm

    Returns: is or not success

    """
    # 构建旧RPM包
    print("*" * 30 + " start build old rpm %s" % rpm + "*" * 30)
    log_build_old = init_log("autoimport", rpm, "build_old_rpm")
    binary_rpm_tmp_path = os.path.join(CURRENT_PATH, "build_rpm/tmp")
    build_command = "osc build --no-verify --root=%s" % binary_rpm_tmp_path
    build_result = subprocess.run(build_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8",
                                  shell=True)
    if build_result.returncode != 0:
        log_build_old.error("build old rpm {} failed,reason is {}".format(rpm, build_result.stderr))
        return 1
    else:
        log_build_old.info("build old rpm %s success" % rpm)

        remove_files(OLD_RPM_PATH)
        copy_files(os.path.join(binary_rpm_tmp_path, "home/abuild/rpmbuild/RPMS/aarch64"), OLD_RPM_PATH)
        copy_files(os.path.join(binary_rpm_tmp_path, "home/abuild/rpmbuild/RPMS/i386"), OLD_RPM_PATH)
        copy_files(os.path.join(binary_rpm_tmp_path, "home/abuild/rpmbuild/RPMS/noarch"), OLD_RPM_PATH)
        return 0


def build_new_rpm(rpm):
    """
    build new rpm
    Args:
        rpm: rpm

    Returns: is or not success

    """
    # 构建新的RPM包
    print("*" * 30 + " start build new rpm %s" % rpm + "*" * 30)
    log_build_new = init_log("autoimport", rpm, "build_new_rpm")
    binary_rpm_tmp_path = os.path.join(CURRENT_PATH, "build_rpm/tmp")
    back_spec = rpm + ".spec~"
    new_release = 2
    if os.path.isfile(back_spec):
        with open(back_spec, "r") as f:
            for line in f.readlines():
                line = line.strip("\n")
                if RELEASE_KEY in line:
                    old_release = line.replace(" ", "").split(":")[1].split("%")[0]
                    new_release = int(old_release) + 1
                    log_build_new.info("new release is %d" % new_release)
                    break
    build_command = "osc build --no-verify --release={} --root={}".format(new_release, binary_rpm_tmp_path)
    build_result = subprocess.run(build_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8",
                                  shell=True)
    if build_result.returncode != 0:
        log_build_new.error("build new rpm {} failed,reason is {}".format(rpm, build_result.stderr))
        return 1
    else:
        log_build_new.info("build new rpm %s success" % rpm)
        remove_files(NEW_RPM_PATH)
        copy_files(os.path.join(binary_rpm_tmp_path, "home/abuild/rpmbuild/RPMS/aarch64"), NEW_RPM_PATH)
        copy_files(os.path.join(binary_rpm_tmp_path, "home/abuild/rpmbuild/RPMS/i386"), NEW_RPM_PATH)
        copy_files(os.path.join(binary_rpm_tmp_path, "home/abuild/rpmbuild/RPMS/noarch"), NEW_RPM_PATH)
        return 0


def rpm_check_fail(rpm_check_result, rpm):
    """
    rpm check
    Args:
        rpm_check_result: check result
        rpm: rpm

    Returns: is or not success

    """
    if rpm_check_result != 0:
        errmsg = "{} binary rpm check fail,log is {}".format(
            rpm, CURRENT_PATH + "/Logs/" + rpm + "/rpm_check.log")
        record_fail_log(errmsg)
        return True
    else:
        return False


def init_log(module, rpm, log_file_name):
    """
    init log
    Args:
        module: logger
        rpm: rpm
        log_file_name: log file

    Returns: log instance

    """
    log = logger.init(module)
    logger.add_file_handler(log, rpm, log_file_name)
    return log


def copy_files(srcpath, targetpath):
    """
    copy file in path
    Args:
        srcpath: source path
        targetpath: target path

    Returns: NONE

    """
    if os.path.exists(srcpath):
        for file in os.listdir(srcpath):
            file_path = os.path.join(srcpath, file)
            if not os.path.exists(targetpath):
                os.mkdir(targetpath)
            shutil.copy(file_path, targetpath)


def remove_files(path):
    """
    remove files in path
    Args:
        path: path

    Returns: NONE

    """
    if os.path.exists(path):
        for file in os.listdir(path):
            os.remove(os.path.join(path, file))


def record_fail_log(errmsg):
    """
    record fail log in file
    Args:
        errmsg: massage

    Returns: NONE

    """
    print("*" * 30 + errmsg + "*" * 30 + "continue!!!")
    with open(os.path.join(CURRENT_PATH, "FailList.txt"), "a") as f1:
        f1.write(errmsg)
        f1.write("\n")


def record_success_log(rpm):
    """
    record success log
    Args:
        rpm: rpm

    Returns: NONE

    """
    print("*" * 30 + "import %s success" % rpm + "*" * 30)
    with open(os.path.join(CURRENT_PATH, "SuccessList.txt"), "a") as f1:
        f1.write(rpm)
        f1.write("\n")


def create_yaml(rpm):
    """
    create yaml
    Args:
        rpm: rpm

    Returns: NONE

    """
    print("*" * 30 + " start create yaml of rpm %s" % rpm + "*" * 30)
    yaml = rpm + ".yaml"
    if not os.path.exists(yaml):
        with open(yaml, "w") as yaml_file:
            yaml_file.write("version: \n")
            yaml_file.write("src_repo: \n")
            yaml_file.write("tag_prefix: \n")
            yaml_file.write("separator: \n")


def update_username_email(spec_prepare_file, user_email, user_name):
    """
    update spec change log
    Args:
        spec_prepare_file: spec file
        user_email: email
        user_name: user

    Returns: NONE

    """
    with open(spec_prepare_file, "r") as src:
        content = src.read()
    with open(spec_prepare_file, "w") as tar:
        content1 = content.replace("name='xxxxxx'", "name='%s'" % user_name)
        content2 = content1.replace("email='xxxxxx@huawei.com''", "email='%s'" % user_email)
        tar.write(content2)


if __name__ == '__main__':
    main()
